package baseclass.dal;

import cn.bidlink.base.ServiceResult;
import cn.bidlink.base.util.PageSet;
import cn.bidlink.procurement.survey.demand.dal.entity.BaseEntity;
import cn.bidlink.procurement.survey.demand.dal.service.BaseService;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

public class BaseServiceImpl<M extends BaseDao<T>, T extends BaseEntity> implements BaseService<T> {

    protected Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    protected M baseDao;

    @Override
    public ServiceResult<Long> save(T entity) {
        ServiceResult<Long> result = new ServiceResult<Long>();
        try {
            baseDao.insert(entity);
            result.setResult(entity.getId());
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#insert",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用save方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<Long> insertSelective(T entity) {
        ServiceResult<Long> result = new ServiceResult<Long>();
        try {
            baseDao.insertSelective(entity);
            result.setResult(entity.getId());
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#insert",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用save方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<Integer> update(T entity) {
        ServiceResult<Integer> result = new ServiceResult<>();
        try {
            result.setResult(baseDao.update(entity));
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+"#update",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用update方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<Integer> updateBatch(List<T> entityList) {
        ServiceResult<Integer> result = new ServiceResult<>();
        try{
            result.setResult(baseDao.updateBatch(entityList));
        }catch(Exception e){log.error("调用{}方法 异常", this.getClass()+".updateBatch]");
            log.error("方法使用参数：[entityList:{}]", entityList);
            log.error("异常信息：{}", e);
            result.setErrMessage("调用updateBatch方法异常，异常信息：" + e.getMessage());
        }

        return result;
    }

    @Override
    public ServiceResult<Integer> delete(Long id) {
        ServiceResult<Integer> result = new ServiceResult<>();
        try {
            result.setResult(baseDao.delete(id));
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#delete",e);
            log.error("方法使用参数：[{}]", id);
            result.setErrMessage("调用delete方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<Integer> deleteBatch(List<Long> ids) {
        ServiceResult<Integer> result = new ServiceResult<>();
        try{
            int row = baseDao.deleteBatch(ids);
            result.setResult(row);
        }catch(Exception e){
            log.error("调用{}方法 异常", this.getClass()+".delete]");
            log.error("方法使用参数：[ids:{}]", ids);
            log.error("异常信息：{}", e);
            result.setErrMessage("调用delete方法异常，异常信息：" + e.getMessage());
        }

        return result;
    }

    @Override
    public ServiceResult<Integer> deleteByCondition(T entity) {
        ServiceResult<Integer> result = new ServiceResult<>();
        try {
            result.setResult(baseDao.deleteByCondition(entity));
        } catch (Exception e) {
            log.error("调用{}方法 异常",  this.getClass()+".#deleteByCondition",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用根据条件删除失败方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<T> findByPK(Long id) {
        ServiceResult<T> result = new ServiceResult<>();
        try {
            result.setResult(baseDao.getByPk(id));
        } catch (Exception e) {
            log.error("调用{}方法 异常",  this.getClass()+".#findByPK",e);
            log.error("方法使用参数：[{}]", id);
            result.setErrMessage("调用findByPK方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<Long> getTotalCount(T entity) {
        ServiceResult<Long> result = new ServiceResult<Long>();
        try {
            result.setResult(baseDao.findCount(entity));
        } catch (Exception e) {
            log.error("调用{}方法 异常",  this.getClass()+".#getTotalCount",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用getTotalCount方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public <E extends PageSet> ServiceResult<List<T>> findByCondition(T entity, E pageSet) {
        ServiceResult<List<T>> result = new ServiceResult<>();
        List<T> list;
        try {
            Page<Object> objects = null;
            if (pageSet != null && pageSet.getPageNum() != null && pageSet.getPageSize() != null) {
                objects = PageHelper.startPage(pageSet.getPageNum(), pageSet.getPageSize());
            }
            if (pageSet != null && StringUtils.isNotBlank(pageSet.getSortColumn())) {
                String orderSql = pageSet.getSortColumn();
                if(null != pageSet.getAsc()){
                    if(pageSet.getAsc()){//正序
                        orderSql = orderSql+" asc ";
                    }else{//逆序
                        orderSql = orderSql+" desc ";
                    }
                }
                PageHelper.orderBy(orderSql);
            }
            list = baseDao.findByCondition(entity);
            result.setResult(list);
            if (objects != null) {
                result.setTotal(objects.getTotal());
            } else {
                result.setTotal(0L);
            }
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#findByCondition",e);
            log.error("方法使用参数：[{},{}]", JSON.toJSONString(entity), JSON.toJSONString(pageSet));
            result.setErrMessage("调用findByCondition方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<List<T>> findByCondition(T entity) {
        ServiceResult<List<T>> result = new ServiceResult<>();
        try {
            result.setResult(baseDao.findByCondition(entity));
            result.setTotal(baseDao.findCount(entity));
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#findByCondition",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用findByCondition方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<List<T>> findByIds(List<Long> ids) {
        ServiceResult<List<T>> result = new ServiceResult<>();
        try {
            result.setResult(baseDao.findByIds(ids));
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#findByIds",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(ids));
            result.setErrMessage("调用findByIds方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    @Override
    public ServiceResult<Integer> insertBatch(List<T> entityList) {
        ServiceResult<Integer> result = new ServiceResult<>();
        try {
            //TODO 临时解决批量插入问题。以后需要再sql上解决
            for(T entity:entityList){
                baseDao.insertSelective(entity);
            }
            result.setResult(entityList.size());
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#insertBatch",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entityList));
            result.setErrMessage("调用insertBatch方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }


    @Override
    public ServiceResult<Integer> insertSelectiveBatch(List<T> entity) {
        ServiceResult<Integer> result = new ServiceResult<Integer>();
        try {
//            Map<String,Object> insertParams = new HashMap<>();
//            List<String> selective = findSelectiveCloums(entity.get(0));
//            insertParams.put("selective",selective);
//            List<Map<String,Object>> dataMaps =  findSelectiveData(entity);
//            log.info("findSelectiveData result={}",JSON.toJSONString(dataMaps));
//            insertParams.put("list",dataMaps);
            Integer rows = baseDao.batchInsertSelective(entity);
            result.setResult(rows);
        } catch (Exception e) {
            log.error("调用{}方法 异常", this.getClass()+".#insert",e);
            log.error("方法使用参数：[{}]", JSON.toJSONString(entity));
            result.setErrMessage("调用save方法异常，异常信息：" + e.getMessage());
        }
        return result;
    }

    /**
     * 获取选择的列名
     * @param t
     * @return
     */
    private List<String> findSelectiveCloums(T t) throws Exception{
        List<String> selectiveCloums = new ArrayList<>();
        Class clazz = t.getClass();
        selectiveCloums = Arrays.stream(clazz.getDeclaredFields())
                .collect(Collectors.toList()).stream().map(el->{
                    String feildName = null;
                    if(el.getName().equals("serialVersionUID")){
                        return feildName;
                    }
                    String getMethodName = "get"+el.getName().substring(0, 1).toUpperCase()
                            + el.getName().substring(1);
                    try {
                        Method getMethod =clazz.getMethod(getMethodName);
                        Object result = getMethod.invoke(t);
                        if(null != result){
                            feildName = el.getName();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return feildName;
                }).filter(el->null != el).collect(Collectors.toList());
        selectiveCloums.remove(null);
        selectiveCloums.add("id");
        return selectiveCloums;
    }

    /**
     * 将传入的值转为批量插入的map集合
     * @param ts
     * @return
     */
    private List<Map<String,Object>> findSelectiveData(List<T> ts){
        List<Map<String,Object>> results = new ArrayList<>();
        results = ts.stream().map(el->{
            Map<String,Object> dataMaps1 = new LinkedHashMap<>();
            List<Map<String,Object>> dataMaps = new ArrayList<>();
            Class clazz = el.getClass();
            Map<String,Object> idMap = new HashMap<>();
            idMap.put("key","id");
            idMap.put("value",el.getId());
            dataMaps.add(idMap);
            dataMaps.addAll(Arrays.stream(clazz.getDeclaredFields())
                    .collect(Collectors.toList()).stream().map(field -> {
                        Map<String,Object> dataMap = new HashMap<>();
                        if(field.getName().equals("serialVersionUID")){
                            dataMap = null;
                            return dataMap;
                        }
                        if(!field.getName().equals("serialVersionUID")){
                            String getMethodName = "get"+field.getName().substring(0, 1).toUpperCase()
                                    + field.getName().substring(1);
                            try {
                                Method getMethod =clazz.getMethod(getMethodName);
                                Object result = getMethod.invoke(el);
                                if(null != result){
                                    dataMap.put("key",field.getName());
                                    dataMap.put("value",result);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        return dataMap;
                    }).filter(dataMap->null != dataMap).collect(Collectors.toList()));
            dataMaps1.put("selective",dataMaps);
            return dataMaps1;
        }).collect(Collectors.toList());
        return results;
    }


    @Override
    public BaseDao<T> getBaseDao() {
        return this.getBaseDao();
    }
}
